﻿using UnityEngine;
using System.Collections;

/// <summary>
/// abstract class for state.
/// </summary>
public abstract class wsState : MonoBehaviour
{
	protected wsStateMachine stateMachine;
	protected bool goNext = false;
	public wsState nextState;

	public abstract string Name { get; }
	public abstract void Enter();
	public abstract void RunLogic();
	public abstract void RunGui();
	public abstract void RunEvent(int eventID);
	public abstract void Exit();

	protected void UnknownEventError(int eventID)
	{
		Debug.LogError("Unknown EventID(" + eventID + ") is found in " + Name);
	}

	public void Init(wsStateMachine fsm)
	{
		if (stateMachine == null)
			stateMachine = fsm;

		this.goNext = false;
	}

	public bool GoNextState()
	{
		if (goNext == false)
		{
			if (stateMachine == null)
				Debug.LogError("state machine is null");

			if (nextState != null)
			{
				stateMachine.SetState(nextState);
				goNext = true;
			}

			return true;
		}
		else
		{
			return false;
		}		
	}
}

/// <summary>
/// machine to manage state.
/// </summary>
[AddComponentMenu("wsLibrary/Design Pattern/Finite State Machine")]
public class wsStateMachine : MonoBehaviour
{
	private wsState currentState;
	public wsState startState;
	public bool dontDestroy = false;
	private bool running = false;

	public static wsStateMachine Instance
	{
		get
		{
			return wsSingletonObject<wsStateMachine>.Instance;
		}
	}

	void Awake()
	{
		if (dontDestroy)
			wsSingletonObject<wsStateMachine>.Awake(gameObject);
	}

	void Start()
	{
		SetState(startState);
	}

	void Update()
	{
		if (running)
		{
			currentState.RunLogic();
		}
	}

	void OnGUI()
	{
		GUI.depth = 0;

		if (running)
		{
			currentState.RunGui();
		}
	}

	public void OnEvent(int eventID)
	{
		if (running)
		{
			currentState.RunEvent(eventID);
		}
	}

	public void SetState(wsState state)
	{
		if (state != null)
		{
			if (currentState != null)
				currentState.Exit();

			currentState = state;
			currentState.Init(this);
			currentState.Enter();
			running = true;
		}
		else
		{
			running = false;
			Debug.LogError("SimpleFSM error : the state is null.");
		}
	}

	public wsState GetState()
	{
		return currentState;
	}

	public string GetStateName()
	{
		return currentState.Name;
	}
}
